﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;
using GigaSite.Domain.Entities;
using GigaSite.Domain.Enums;
using GigaSite.Domain.Interfaces.Repositories;
using GigaSite.Domain.IoC;
using GigaSite.Web.Areas.ControlPanel.Models;
using GigaSite.Web.Models;

namespace GigaSite.Web.Areas.ControlPanel.Controllers
{
    /// <summary>
    /// Контроллер управления каталогом сайтов
    /// </summary>
    public class ManageSitesController : BaseRootController
    {
        //
        // GET: /ControlPanel/ManageSites/
        /// <summary>
        /// Отображает панель управления каталогом сайтов
        /// </summary>
        /// <returns></returns>
        public ActionResult Index()
        {
            return View();
        }

        /// <summary>
        /// Возвращает коллекцию сайтов удовлетворяющих определенному фильтру на клиент
        /// </summary>
        /// <param name="filter">Тип фильтра</param>
        /// <returns>Коллекция сайтов в Json формате</returns>
        [HttpPost]
        public JsonResult GetSites(string filter)
        {
            try
            {
                // Репозиторий
                var repository = Locator.GetService<ISitesRepository>();

                // Делаем выборку
                IEnumerable<Site> dbSites = Enumerable.Empty<Site>();
                switch (filter)
                {
                    case "all":
                        dbSites = repository.FindAll();
                        break;
                    case "moderated":
                        dbSites = repository.Search(s => s.Status == SiteStatuses.InChecking);
                        break;
                    default:
                        break;
                }

                // Преобразуем в модели
                var sites = dbSites.OrderByDescending(s => s.DateCreated).Select(s => new SiteModel(s)).AsEnumerable();

                // Отдаем результат
                return JsonSuccess(sites);
            }
            catch (Exception e)
            {
                return JsonErrors(e);
            }
        }

        /// <summary>
        /// Возвращает древо категорий для сайта с указанными идентификатором
        /// </summary>
        /// <param name="id">Идентификатор сайта</param>
        /// <returns>Древо категорий</returns>
        [HttpPost]
        public JsonResult GetCategories(long id)
        {
            try
            {
                // Репозиторий
                var repository = Locator.GetService<ISitesRepository>();

                // Загружаем сайт
                Site site = null;
                if (id > 0)
                {
                    site = repository.Load(id);
                }

                // Строим древо категорий
                var categories = new List<ExtJSTreeNodeModel>();
                EnumerateSiteCategories(-1, categories, site);

                // Отдаем результат
                return new JsonNetResult()
                {
                    Data = categories,
                    ContentEncoding = Encoding.UTF8,
                    ContentType = "application/json",
                    JsonRequestBehavior = JsonRequestBehavior.AllowGet
                };
            }
            catch (Exception e)
            {
                return JsonErrors(e);
            }
        }

        /// <summary>
        /// Рекурсивно строит дерево категорий, в процессе делая каждую категорию помеченной если в ней присутствует указанный сайт
        /// </summary>
        /// <param name="parentId">Родительский идентификатор</param>
        /// <param name="categoriesList">список категорий</param>
        /// <param name="site">сайт</param>
        private void EnumerateSiteCategories(long parentId, List<ExtJSTreeNodeModel> categoriesList, Site site)
        {
            var repository = Locator.GetService<ICategoriesRepository>();
            categoriesList.AddRange(repository.GetChildCategories(parentId).Select(c => new CategoryTreeNodeModel()
                                                                                            {
                                                                                                Expanded = true,
                                                                                                Id = c.Id,
                                                                                                Text = c.DisplayName,
                                                                                                Tooltip = c.Description,
                                                                                                Leaf = false,
                                                                                                Category =
                                                                                                    {
                                                                                                        Description =
                                                                                                            c.
                                                                                                            Description,
                                                                                                        DisplayName =
                                                                                                            c.
                                                                                                            DisplayName,
                                                                                                        Hidden =
                                                                                                            c.Hidden,
                                                                                                        SystemName =
                                                                                                            c.SystemName,
                                                                                                        Id =
                                                                                                            c.Id.
                                                                                                            ToString(),
                                                                                                        ParentId =
                                                                                                            c.ParentId.
                                                                                                            ToString()
                                                                                                    },
                                                                                                Childrens =
                                                                                                    new List
                                                                                                    <ExtJSTreeNodeModel>
                                                                                                    (),
                                                                                                Checked = site != null && c.SiteToCategoryMappings.Any(m => m.SiteId == site.Id)
                                                                                            }));
            foreach (CategoryTreeNodeModel category in categoriesList)
            {
                EnumerateSiteCategories(category.Id, category.Childrens,site);
            }
        }

        /// <summary>
        /// Обрабатывает сохранение сайта с клиента, создает или обновляет существующий
        /// </summary>
        /// <param name="id">Идентификатор сайта</param>
        /// <param name="url">URL</param>
        /// <param name="title">Название</param>
        /// <param name="description">Описание</param>
        /// <param name="city">Город</param>
        /// <param name="status">Статус</param>
        /// <param name="categories">Идентификаторы категорий</param>
        /// <returns></returns>
        [HttpPost]
        public JsonResult Save(long id, string url, string title, string description, string city, short status, string categories)
        {
            try
            {
                // Репозитории
                var categoriesRepository = Locator.GetService<ICategoriesRepository>();
                var sitesRepository = Locator.GetService<ISitesRepository>();

                // Парсим и загружаем установленные категории для сайта
                var cats =
                    categories.Split(new[] {","}, StringSplitOptions.RemoveEmptyEntries).Select(s => Convert.ToInt64(s))
                        .Select(categoriesRepository.Load).Where(c => c != null).AsEnumerable();

                Site site = null;
                // Проверяем что за действие сейчас выполняется
                if (id < 0)
                {
                    // Идет создание нового сайта
                    site = new Site()
                               {
                                   City = city,
                                   DateCreated = DateTime.Now,
                                   Status = (SiteStatuses) status,
                                   Title = title,
                                   URL = url,
                                   Description = description
                               };
                    sitesRepository.Add(site);
                }
                else
                {
                    // Редактируем изменения по сайту
                    site = sitesRepository.Load(id);
                    if (site == null)
                    {
                        throw new ObjectNotFoundException(string.Format("Сайт с идентификатором {0} не найден", id));
                    }

                    site.DateModified = DateTime.Now;
                    site.City = city;
                    site.Status = (SiteStatuses) status;
                    site.Title = title;
                    site.URL = url;
                    site.Description = description;
                }

                // Устанавливаем категории в которых сайт должен находиться
                sitesRepository.SetSiteCategories(site, cats);

                // Сабмитим
                sitesRepository.SubmitChanges();

                // Отдаем успешный результат
                return JsonSuccess(new {id = site.Id});
            }
            catch (Exception e)
            {
                return JsonErrors(e);
            }
        }

        /// <summary>
        /// Удаляет указанный сайт из каталога
        /// </summary>
        /// <param name="id">Идентификатор сайта</param>
        /// <returns>Сообщение об успехе или неуспехе</returns>
        [HttpPost]
        public JsonResult Delete(long id)
        {
            try
            {
                // Репозиторий
                var repository = Locator.GetService<ISitesRepository>();

                // Ищем и удаляем
                var site = repository.Load(id);
                if (site == null)
                {
                    throw new ObjectNotFoundException(String.Format("Сайт с идентификатором {0} не найден",id));
                }

                repository.Delete(site);
                repository.SubmitChanges();
                
                // Отправяем результат
                return JsonSuccess();
            }
            catch (Exception e)
            {
                return JsonErrors(e);
            }
        }
    }
}
